﻿unit FTPDirectory;

interface

uses
  Winapi.Windows, System.Classes, System.SysUtils;

type
  TOPKind = (opUpload, opDownLoad);
  TFileState = ( tfsUploadWait, tfsUploading, tfsUpLoadTerminate, tfsUpLoadSucess,
                 tfsDownLoadWait, tfsDownLoading, tfsDownLoadTerminate, tfsDownLoadSucess );

  PTFileNodeItem = ^TFileNodeItem;
  TFileNodeItem = packed record
    sFileIndex:       Cardinal;                          //文件索引
    sFilePath:        array[0..2048] of char;         //文件路径
    sFileName:        array[0..255] of char;          //文件名
    sFileSize:        Int64;                          //文件大小
    sFileAttr:        array[0..50] of char;           //文件属性
    sCreateTime:      array[0..19] of char;           //创建时间
    sLastAccessTime:  array[0..19] of char;           //访问时间
    sLastWriteTime:   array[0..19] of char;           //修改时间
    opTime:           Cardinal;                          //执行时间
    OPKind:           TOPKind;                        //操作类型
    FileState:        TFileState;                     //操作状态
  end;

  TFTPDirectory = class
  protected
    m_sUpLoadPath: String;
    m_sDownLoadPath: String;
    m_DownLoadList: TList;
    m_UpLoadList:   TList;
  published
    property FUpLoadPath: String read m_sUpLoadPath write m_sUpLoadPath;
    property FDownLoadPath: String read m_sDownLoadPath write m_sDownLoadPath;

  private
    function GetFileAttrs(iAttrs: Integer):String;
    procedure SetFileAttrs(const sFilePath, sFileAttrib: String);
    procedure FindFileList(sDirectoryPath: string; SFileList: TList; OPKind: TOPKind);

  //上传相关
  public
    function FindUpLoadFile(sFileName: String): Boolean;
    function GetUpLoadFileInfo(iFileIndex: Integer): PTFileNodeItem;
    function GetUpLoadFileCount: WORD;
    function GetUpLoadFile: PTFileNodeItem;
    function AddFileUpLoad(sPathFile: String): Boolean;
    function DeleteFileUpLoad(sPathFile: String): Boolean;
    procedure CreateUpLoadDirectory;
    
 //下载相关
 public
    procedure LoadAllFileList;
    function GetDownLoadFileCount: WORD;
    function AddFileDownLoad(dFileIndex: Cardinal; sFileSize: Int64; sFileName: String): Boolean;
    function GetDownLoadFileInfo(iFileIndex: Integer): PTFileNodeItem;
    function DeleteFileDownLoad(sFileName: String): Boolean;
    function GetDownLoadFile: PTFileNodeItem;
    procedure CreateDownLoadDirectory;
    procedure ClearDownFileList;

  public
    constructor Create;
    destructor Destroy; override;
  end;

implementation

constructor TFTPDirectory.Create;
begin
  inherited Create;
  m_sUpLoadPath := '';
  m_sDownLoadPath := '';
  m_DownLoadList := TList.Create;
  m_UpLoadList := TList.Create;
end;

destructor TFTPDirectory.Destroy;
var
  I: Integer;
begin
  if m_UpLoadList.Count>0 then begin
    for I:=0 to m_UpLoadList.Count-1 do
      Dispose(m_UpLoadList.Items[I]);
  end;
  m_UpLoadList.Free;

  if m_DownLoadList.Count>0 then begin
    for I:=0 to m_DownLoadList.Count-1 do
      Dispose(m_DownLoadList.Items[I]);
  end;
  m_DownLoadList.Free;
  inherited Destroy;
end;

//上传相关
function TFTPDirectory.GetUpLoadFileInfo(iFileIndex: Integer): PTFileNodeItem;
begin
  Result := nil;
  if m_UpLoadList.Count > 0 then
  if (iFileIndex >= 0) and (iFileIndex <= m_UpLoadList.Count-1) then
    Result := PTFileNodeItem(m_UpLoadList.Items[iFileIndex]);
end;

procedure TFTPDirectory.CreateUpLoadDirectory;
var
  sPath: string;
begin
  sPath := ExtractFilePath(ParamStr(0))+'UpLoad\';
  if not DirectoryExists(sPath) Then
    CreateDir(sPath);
  m_sUpLoadPath := sPath;
end;

function TFTPDirectory.GetUpLoadFileCount: WORD;
var
  i: Integer;
  nUpLoad: WORD;
  pFileNode: PTFileNodeItem;
begin
  nUpLoad := 0;
  for i:=0 to m_UpLoadList.Count - 1 do
  begin
    pFileNode := GetUpLoadFileInfo(i);
    if pFileNode <> nil then
    begin
      if (pFileNode^.OPKind = opUpload) and
         (pFileNode^.FileState = tfsUploadWait) then
        Inc(nUpLoad);
    end;
  end;
  Result := nUpLoad;
end;

function TFTPDirectory.FindUpLoadFile(sFileName: String): Boolean;
var
  I: Integer;
begin
  Result := FALSE;
  if m_UpLoadList.Count>0 then
    For I:=0 to m_UpLoadList.Count-1 do begin
      if PTFileNodeItem(m_UpLoadList.Items[I])^.sFileName = sFileName then
      begin
        Result := TRUE;
        break;
       end;
    end;
end;

function TFTPDirectory.DeleteFileUpLoad(sPathFile: String): Boolean;
var
  I: Integer;
begin
  Result := FALSE;
  if m_UpLoadList.Count>0 then
    For I:=0 to m_UpLoadList.Count-1 do begin
      if PTFileNodeItem(m_UpLoadList.Items[I])^.sFileName = sPathFile then
      begin
        m_UpLoadList.Delete(I);
        Result := TRUE;
        break;
       end;
    end;
end;

function TFTPDirectory.GetUpLoadFile: PTFileNodeItem;
var
  i: Integer;
  pFileNode: PTFileNodeItem;
begin
  Result := nil;
  for i := 0 to m_UpLoadList.Count - 1 do
  begin
    pFileNode := GetUpLoadFileInfo(i);
    if pFileNode<>nil then
    begin
      if (pFileNode^.OPKind = opUpload) and
         (pFileNode^.FileState = tfsUploadWait) then
      begin
        Result := pFileNode;
        break;
      end;
    end;
  end;
end;

function TFTPDirectory.AddFileUpLoad(sPathFile: String): Boolean;
var
  SearchRec: TSearchRec;
  SysTime: TSystemTime;
  pFileNode: PTFileNodeItem;
begin
  if FindFirst(sPathFile, faAnyfile, SearchRec) = 0 Then begin

    try
      if not FindUpLoadFile(SearchRec.Name) then begin
        New(pFileNode);
        FillChar(pFileNode^.sFilePath, 1024, 0);
        StrPCopy(pFileNode^.sFilePath, sPathFile);
        FillChar(pFileNode^.sFileName, 256, 0);
        StrPCopy(pFileNode^.sFileName, SearchRec.Name);
        pFileNode^.sFileSize := SearchRec.FindData.nFileSizeLow or Int64(SearchRec.FindData.nFileSizeHigh) shl 32;

        //创建时间
        FileTimeToSystemTime(SearchRec.FindData.ftCreationTime, SysTime);
        StrPCopy(pFileNode^.sCreateTime, FormatDateTime('YYYY-MM-DD HH:MM:SS', SystemTimeToDateTime(SysTime)));
        FileTimeToSystemTime(SearchRec.FindData.ftLastAccessTime, SysTime);
        StrPCopy(pFileNode^.sLastAccessTime, FormatDateTime('YYYY-MM-DD HH:MM:SS', SystemTimeToDateTime(SysTime)));
        FileTimeToSystemTime(SearchRec.FindData.ftLastWriteTime, SysTime);
        StrPCopy(pFileNode^.sLastWriteTime, FormatDateTime('YYYY-MM-DD HH:MM:SS', SystemTimeToDateTime(SysTime)));

        //文件属性
        StrPCopy(pFileNode^.sFileAttr, GetFileAttrs(SearchRec.Attr));
        //上传, 等待中
        pFileNode^.OPKind := opUpload;
        pFileNode^.FileState := tfsUploadWait;
        m_UpLoadList.Add(pFileNode);
        Result := True;
      end;
    finally
      FindClose(SearchRec);
    end
  end;
end;

//下载相关
function TFTPDirectory.GetDownLoadFileCount: WORD;
var
  i: Integer;
  nDownLoad: WORD;
  pFileNode: PTFileNodeItem;
begin
  nDownLoad := 0;
  if m_DownLoadList.Count > 0 then
    for i := 0 to m_DownLoadList.Count - 1 do
    begin
      pFileNode := GetDownLoadFileInfo(I);
      if pFileNode<>nil then
      begin
        if (pFileNode^.OPKind = opDownLoad) and
           (pFileNode^.FileState = tfsDownLoadWait) then
          Inc(nDownLoad);
      end;
    end;
  Result := nDownLoad;
end;

procedure TFTPDirectory.ClearDownFileList;
var
  I: Integer;
begin
  if m_DownLoadList.Count>0 then
    For I:=m_DownLoadList.Count-1 downto 0 do begin
      m_DownLoadList.Delete(I);
    end;
end;

function TFTPDirectory.DeleteFileDownLoad(sFileName: String): Boolean;
var
  I: Integer;
begin
  Result := FALSE;
  if m_DownLoadList.Count>0 then
    For I:=0 to m_DownLoadList.Count-1 do begin
      if PTFileNodeItem(m_DownLoadList.Items[I])^.sFileName = sFileName then
      begin
        m_DownLoadList.Delete(I);
        Result := TRUE;
        break;
       end;
    end;
end;

function TFTPDirectory.AddFileDownLoad(dFileIndex: Cardinal; sFileSize: Int64; sFileName: String): Boolean;
var
  pFileNode: PTFileNodeItem;
begin
   New(pFileNode);
   FillChar(pFileNode^.sFilePath, 1024, 0);
   FillChar(pFileNode^.sFileName, 256, 0);
   StrPCopy(pFileNode^.sFileName, sFileName);
   pFileNode^.sFileSize := sFileSize;
   pFileNode^.sFileIndex := dFileIndex;
   //下载, 等待中
   pFileNode^.OPKind := opDownLoad;
   pFileNode^.FileState := tfsDownLoadWait;
   m_DownLoadList.Add(pFileNode);
   Result := TRUE;
end;

function TFTPDirectory.GetDownLoadFileInfo(iFileIndex: Integer): PTFileNodeItem;
begin
  Result := nil;
  if m_DownLoadList.Count > 0 then
  if (iFileIndex >= 0) and (iFileIndex < m_DownLoadList.Count) then
    Result := PTFileNodeItem(m_DownLoadList.Items[iFileIndex]);
end;

function TFTPDirectory.GetDownLoadFile: PTFileNodeItem;
var
  i: Integer;
  pFileNode: PTFileNodeItem;
begin
  Result := nil;
  for i := 0 to m_DownLoadList.Count - 1 do
  begin
    pFileNode := GetDownLoadFileInfo(I);
    if pFileNode<>nil then
    begin
      if (pFileNode^.OPKind = opDownload) and
         (pFileNode^.FileState = tfsDownloadWait) then
      begin
        Result := pFileNode;
        break;
      end;
    end;
  end;
end;

procedure TFTPDirectory.CreateDownLoadDirectory;
var
  sPath: string;
begin
  sPath := ExtractFilePath(ParamStr(0))+'DownLoad\';
  if not DirectoryExists(sPath) Then
    CreateDir(sPath);
  m_sDownLoadPath := sPath;
end;

procedure TFTPDirectory.FindFileList(sDirectoryPath: string; sFileList: TList; OPKind: TOPKind);
var
  SearchRec: TSearchRec;
  SysTime: TSystemTime;
  FileAttrs: Integer;
  pFileNode: PTFileNodeItem;
begin
  FileAttrs := faAnyFile or faDirectory;
  SFileList.Clear;
  if FindFirst(sDirectoryPath + '*.*', FileAttrs, SearchRec) = 0 then
  begin
    repeat
      if ((SearchRec.Attr and FileAttrs) = SearchRec.Attr) and
         (SearchRec.Name <> '.') and
         (SearchRec.Name <> '..') then
      begin
        New(pFileNode);
        FillChar(pFileNode^.sFileName, 256, 0);
        StrPCopy(pFileNode^.sFileName, SearchRec.Name);
        pFileNode^.sFileSize := SearchRec.FindData.nFileSizeLow or Int64(SearchRec.FindData.nFileSizeHigh) shl 32;
        //创建时间
        FileTimeToSystemTime(SearchRec.FindData.ftCreationTime, SysTime);
        StrPCopy(pFileNode^.sCreateTime, FormatDateTime('YYYY-MM-DD HH:MM:SS', SystemTimeToDateTime(SysTime)));
        FileTimeToSystemTime(SearchRec.FindData.ftLastAccessTime, SysTime);
        StrPCopy(pFileNode^.sLastAccessTime, FormatDateTime('YYYY-MM-DD HH:MM:SS', SystemTimeToDateTime(SysTime)));
        FileTimeToSystemTime(SearchRec.FindData.ftLastWriteTime, SysTime);
        StrPCopy(pFileNode^.sLastWriteTime, FormatDateTime('YYYY-MM-DD HH:MM:SS', SystemTimeToDateTime(SysTime)));
        //文件属性
        StrPCopy(pFileNode^.sFileAttr, GetFileAttrs(SearchRec.Attr));
        pFileNode^.OPKind := OPKind;
        if OPKind = opUpload then
          pFileNode^.FileState := tfsUploadWait
        else
          pFileNode^.FileState := tfsDownLoadWait;
        sFileList.Add(pFileNode);
      end;
    until FindNext(SearchRec) <> 0;
    FindClose(SearchRec);
  end;
end;

procedure TFTPDirectory.LoadAllFileList;
var
  i: Integer;
begin
  if m_UpLoadList.Count > 0 then
    for i := 0 to m_UpLoadList.Count - 1 do Dispose(m_UpLoadList.Items[i]);
  if m_DownLoadList.Count > 0 then
    for i := 0 to m_DownLoadList.Count - 1 do Dispose(m_DownLoadList.Items[i]);
  FindFileList(m_sUpLoadPath,  m_UpLoadList, opUpload);
  FindFileList(m_sDownLoadPath, m_DownLoadList, opDownLoad);
end;

function TFTPDirectory.GetFileAttrs(iAttrs: Integer):String;
var
  sAttr: String;
begin
  sAttr := '';
  if (iAttrs and faReadOnly)  = faReadOnly  then sAttr := sAttr+'只读-';
  if (iAttrs and faHidden)    = faHidden    then sAttr := sAttr+'隐藏-';
  if (iAttrs and faSysFile)   = faSysFile   then sAttr := sAttr+'系统-';
  if (iAttrs and faVolumeID)  = faVolumeID  then sAttr := sAttr+'卷标-';
  if (iAttrs and faDirectory) = faDirectory then sAttr := sAttr+'目录-';
  if (iAttrs and faArchive)   = faArchive   then sAttr := sAttr+'存档-';
  if (iAttrs and faAnyFile)   = faAnyFile   then sAttr := sAttr+'文件-';
  Result := Copy(sAttr, 1, Length(sAttr)-1);
end; 

procedure TFTPDirectory.SetFileAttrs(const sFilePath, sFileAttrib: String);
var 
  iAttrs: Integer;
  sAttrs: String;
begin 
  iAttrs := 0;
  sAttrs := UpperCase(sFileAttrib);
  if Pos('R', sAttrs)= 0 then iAttrs:=iAttrs or faReadOnly;
  if Pos('H', sAttrs)= 0 then iAttrs:=iAttrs or faHidden;
  if Pos('S', sAttrs)= 0 then iAttrs:=iAttrs or faSysFile;
  if Pos('V', sAttrs)= 0 then iAttrs:=iAttrs or faVolumeID;
  if Pos('D', sAttrs)= 0 then iAttrs:=iAttrs or faDirectory;
  if Pos('A', sAttrs)= 0 then iAttrs:=iAttrs or faArchive;
  if Pos('Y', sAttrs)= 0 then iAttrs:=iAttrs or faAnyFile;
  FileSetAttr(sFilePath, iAttrs);
end;
 
  
end.



